package com.atguigu.bookcity.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.atguigu.bookcity.entity.User;
import com.atguigu.bookcity.entity.UserRole;
import com.atguigu.bookcity.entity.vo.RegisterVo;
import com.atguigu.bookcity.entity.vo.UserVo;
import com.atguigu.bookcity.exception.BookCityException;
import com.atguigu.bookcity.mapper.UserMapper;
import com.atguigu.bookcity.mapper.UserRoleMapper;
import com.atguigu.bookcity.service.EmailService;
import com.atguigu.bookcity.service.UserRoleService;
import com.atguigu.bookcity.service.UserService;
import com.atguigu.bookcity.utils.Md5;
import com.atguigu.bookcity.utils.RedisUtil;
import com.atguigu.bookcity.vo.CommonResult;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.Serializable;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zsc
 * @since 2021-03-20
 */
@Service("userService")
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private UserRoleService userRoleService;

    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    private EmailService emailService;

    @Override
    public CommonResult register(RegisterVo vo) {
        User user = RegisterUser(vo);
        if (save(user)) {
            user.setRole("user");
            insertRole(user);
            return CommonResult.ok().message("注册成功");
        }

        return CommonResult.error().message("注册失败");
    }

    @Override
    public CommonResult login(String name, String password) {
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(name, password);
        try {
            subject.login(token);
            User user = (User) subject.getPrincipal();
            Serializable sessionId = subject.getSession().getId();
            return CommonResult.ok()
                    .data("userId", user.getId())
                    .data("sessionId", sessionId)
                    .data("username", user.getUsername())
                    .data("role", user.getRole());
        } catch (IncorrectCredentialsException e) {
            throw new IncorrectCredentialsException();
        } catch (ExcessiveAttemptsException e) {
            throw new ExcessiveAttemptsException();
        } catch (UnknownAccountException e) {
            throw new UnknownAccountException();
        }
    }

    @Override
    public void modifyUserRoleById(String userId, String newRole) {
        UserRole userRole = new UserRole();
        userRole.setUserId(userId);
        userRole.setRoleId(userRoleMapper.getRoleIdByName(newRole));
        userRoleService.updateById(userRole);
    }

    @Override
    public boolean modifyPassword(UserVo vo) {
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        if (!isMatched(vo, user)) {
            throw new BookCityException(201, "起始密码输入有误");
        }
        user.setPassword(Md5.encryption(vo.getPassword(), user.getSalt(), 1024));
        return updateById(user);

    }

    @Override
    public void resetPassword(String username) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        User user = getOne(wrapper);
        if (user == null) {
            throw new BookCityException(201, "用户名不存在");
        }
        String randomPassword = RandomUtil.randomString(10);
        user.setPassword(Md5.encryption(randomPassword, user.getSalt(), 1024));
        updateById(user);

        emailService.sendEmail(user.getEmail(),
                "密码重置成功,新密码为: ",
                randomPassword + "\n请勿泄露!!!");

    }

    private boolean isMatched(UserVo vo, User user) {
        return user.getPassword().
                equals(Md5.encryption(vo.getPrimaryPassword(), user.getSalt(), 1024));
    }

    @Override
    public CommonResult adminRegister(RegisterVo vo, String role) {
        User user = RegisterUser(vo);
        if (save(user)) {
            user.setRole(role);
            insertRole(user);
            return CommonResult.ok().message("注册成功");
        }

        return CommonResult.error().message("注册失败");
    }


    public void insertRole(User user) {
        String roleId = userRoleMapper.getRoleIdByName(user.getRole());
        String userId = user.getId();
        UserRole userRole = new UserRole();
        userRole.setUserId(userId);
        userRole.setRoleId(roleId);
        userRoleService.save(userRole);
    }

    public User RegisterUser(RegisterVo vo) {
        Object redisCode = redisUtil.get(vo.getEmail());
        if (redisCode == null)
            throw new BookCityException(201, "邮箱验证码过期");
        if (!redisCode.equals(vo.getCode()))
            throw new BookCityException(201, "验证码输入错误,注册失败");
        if (StringUtils.isEmpty(vo.getUsername()) || StringUtils.isEmpty(vo.getPassword())) {
            throw new BookCityException(201, "用户名或密码不能为空");
        }
        User user = new User();
        BeanUtils.copyProperties(vo, user);
        int count = count(new QueryWrapper<User>().eq("username", user.getUsername()));
        if (count != 0) {
            throw new BookCityException(201, "用户名已存在");
        }
        String salt = RandomUtil.randomString(20);
        user.setSalt(salt);
        user.setPassword(Md5.encryption(user.getPassword(), salt, 1024));
        return user;
    }
}
